﻿using System;
using AIClient.Awaiters;
using NetMsg;
using NetMsg.Gate;
using NetWorkMsg;
using NFX.Erlang;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using NetMsg.Card;
using NetMsg.CardAction;

namespace AIClient.Players.Modules
{
    public static class GateState
    {
        public static int Idle = 0;
        public static int Busy = 1;
    }

    // 管理网络协议数据收发的模块
    public class Gate : Module
    {
        private          int                                                  _state;
        private readonly ConcurrentQueue<byte[]>                              _messageQueue;
        private readonly Dictionary<uint, UnPackableAwaiterWrapper> _wrappers;
        public bool IsInDispatch;

        public Gate(Player player) : base(player)
        {
            _state        = GateState.Idle;
            _messageQueue = new ConcurrentQueue<byte[]>();
            _wrappers     = new Dictionary<uint, UnPackableAwaiterWrapper>();
        }

        //---------------------------------------------------------------------
        //对外接口
        // 异步向服务器推送消息
        public void Send(IIdPackable msg)
        {
            var pool   = Manager.Instance.BufferPool;
            var buffer = pool.Get();
            buffer.Position = 0;
            msg.Pack(buffer);

            var binary = new ErlBinary(buffer.GetBuffer(), 0, (int) buffer.Length);
            Player.Send(binary);
            pool.Put(buffer);
        }

        // 同步向服务器发送消息
        public UnPackableAwaiterWrapper SendAsync(IServerCallbackable msg)
        {
            Send(msg);

            var wrapper = new UnPackableAwaiterWrapper();
            _wrappers[msg.UnPackableId] = wrapper;

            return wrapper;
        }

        public void Dispatch(byte[] binary)
        {
#if DEBUG
            var stream = new MemoryStream(binary, false);
            var id     = UnPackAuxiliary.ReadId(stream);
            var route  = Router.GetRouteInfo(id);
            Console.WriteLine($"收到消息:{route.Factory().GetType().Name}");
#endif
            if (GateState.Idle == Interlocked.CompareExchange(ref _state, GateState.Busy, GateState.Idle))
                Task.Run(() => Decode(binary));
            else _messageQueue.Enqueue(binary);
        }

        // 消息解码、派送
        private void Decode(byte[] binary)
        {
            var stream = new MemoryStream(binary, false);
            var id     = UnPackAuxiliary.ReadId(stream);
            var route  = Router.GetRouteInfo(id);

            if (route != null)
            {
                // 消息解包、派送
                var msg = route.Factory();
                Console.WriteLine($"in {msg.GetType().Name}");
                msg.UnPack(stream);
                IsInDispatch = true;
                Dispatch(id, route, msg);
                IsInDispatch = false;

                Console.WriteLine($"out {msg.GetType().Name}");

                // 触发awiter
                if (_wrappers.TryGetValue(id, out var wrapper))
                {
                    _wrappers.Remove(id);
                    wrapper.SetResult(msg);
                }

                Console.WriteLine($"awiter {msg.GetType().Name}");
            }

            // 状态修改
            if (_messageQueue.IsEmpty)
                Interlocked.Exchange(ref _state, GateState.Idle);
            else if (_messageQueue.TryDequeue(out binary))
                Decode(binary);
            else throw new Exception("消息队列不为空,但无法出队消息");
        }

        // 注销
        public void DoUnLogin()
        {
        }

        // 关闭
        public void Close()
        {
            _messageQueue.Clear();
            _wrappers.Clear();
        }

        //---------------------------------------------------------------------
        // 将消息分发到对应模块去
        private void Dispatch(uint messageId, RouteInfo route, IUnPackable unPackable)
        {
            // 向逻辑Server派发消息
            var msgEnum = route.Message;
            switch (route.Module)
            {
                case ModuleEnum.Gate:
                    Dispatch((GateEnum) msgEnum, unPackable);
                    break;

                case ModuleEnum.Player:
                    break;

                case ModuleEnum.App:
                    break;

                case ModuleEnum.Chat:
                    break;
                case ModuleEnum.Dragon:
                    break;

                case ModuleEnum.Phone:
                    break;

                case ModuleEnum.Card:
                    Player.Card.Dispatch((CardEnum)msgEnum, unPackable);
                    break;

                case ModuleEnum.ParallelWorld:
                    break;

                case ModuleEnum.Wallpaper:
                    break;

                case ModuleEnum.Music:
                    break;

                case ModuleEnum.Hatch:
                    break;

                case ModuleEnum.WishMission:
                    break;

                case ModuleEnum.Equip:
                    break;
                case ModuleEnum.Map:
                    break;

                case ModuleEnum.Food:
                    break;

                case ModuleEnum.CardAction:
                    Player.Card.Dispatch((CardActionEnum)msgEnum, unPackable);
                    break;

                default:
                    break;
            }
        }

        // 分发网关模块的消息
        private static void Dispatch(GateEnum tag, IUnPackable msg)
        {
            switch (tag)
            {
                case GateEnum.HeartP:
                    break;
                case GateEnum.CreateP:
                    break;
                case GateEnum.LoginP:
                    break;
                case GateEnum.KickByReloginP:
                    break;
                default:
                    break;
            }
        }
    }
}